package com.cardone.common.util;

import com.cardone.common.util.support.*;
import com.google.common.reflect.*;
import com.google.gson.*;
import lombok.extern.slf4j.*;
import org.apache.commons.collections.*;
import org.apache.commons.lang3.StringUtils;

import java.lang.reflect.*;
import java.util.*;

/**
 * bean 工具
 *
 * @author yaohaitao
 */
@Slf4j
public class MapperUtils {
    /**
     * 时间解析
     */
    private static DateSerializerSupport dateSerializerSupport = new DateSerializerSupport();

    private static Type mapType = new TypeToken<Map<String, Object>>() {
        /**
         *
         */
        private static final long serialVersionUID = -9096570133906255553L;
    }.getType();
    private static Map<String, Gson> gsonMap = com.google.common.collect.Maps.newConcurrentMap();

    private MapperUtils() {
    }

    /**
     * 获取bean关于json
     *
     * @param mappedClass 映射类型
     * @param jsonString
     * @return bean @
     */
    public static <T> T getBeanForJson(final Class<T> mappedClass, final String jsonString) {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }

        return getBeanForJson(TypeToken.of(mappedClass).getType(), jsonString);
    }

    /**
     * 获取bean关于json
     *
     * @param typeOfT    映射类型
     * @param jsonString
     * @return bean @
     */
    public static <T> T getBeanForJson(Type typeOfT, final String jsonString) {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }

        return builderGson(null).fromJson(jsonString, typeOfT);
    }

    /**
     * 生成gson
     *
     * @param datePattern 日期结构
     * @return
     */
    private static Gson builderGson(final String datePattern) {
        String cacheKey = "datePattern:" + datePattern;

        if (gsonMap.containsKey(cacheKey)) {
            return gsonMap.get(cacheKey);
        }

        com.google.gson.GsonBuilder gsonBuilder = new com.google.gson.GsonBuilder().enableComplexMapKeySerialization().serializeNulls();

        gsonBuilder = gsonBuilder.setPrettyPrinting();

        gsonBuilder.registerTypeAdapter(java.util.Date.class, com.cardone.common.util.MapperUtils.dateSerializerSupport);

        gsonBuilder.setDateFormat(com.cardone.common.util.StringUtils.defaultIfBlank(datePattern, com.cardone.common.util.DateUtils.DEFAULT_DATE_PATTERN));

        Gson gson = gsonBuilder.create();

        gsonMap.put(cacheKey, gson);

        return gson;
    }

    /**
     * 获取bean关于json
     *
     * @param mappedClass 映射类型
     * @param paramName   参数名称
     * @param map
     * @return @
     */
    public static <T> T getBeanForJson(final Class<T> mappedClass, final String paramName, final Map<String, Object> map) {
        final Object paramJsonObject = MapUtils.getObject(map, paramName);

        if (paramJsonObject == null) {
            return null;
        }

        return MapperUtils.toBean(mappedClass, paramJsonObject);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedClass 映射类型
     * @param src
     * @return @
     */
    public static <T> T toBean(final Class<T> mappedClass, final Object src) {
        return MapperUtils.toBean(mappedClass, src, null);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedClass 映射类型
     * @param src
     * @param datePattern 日期结构
     * @return @
     */
    public static <T> T toBean(final Class<T> mappedClass, final Object src, final String datePattern) {
        final Gson gson = MapperUtils.builderGson(datePattern);

        final String srcJsonString = gson.toJson(src);

        return gson.fromJson(srcJsonString, TypeToken.of(mappedClass).getType());
    }

    /**
     * 获取bean关于json
     *
     * @param mappedClass 映射类型
     * @param paramName   参数名称
     * @param jsonString
     * @return bean @
     */
    public static <T> T getBeanForJson(final Class<T> mappedClass, final String paramName, final String jsonString) {
        final Object paramJsonObject = MapperUtils.getObjectForJson(paramName, jsonString);

        if (paramJsonObject == null) {
            return null;
        }

        return MapperUtils.toBean(mappedClass, paramJsonObject);
    }

    /**
     * 获取对象
     *
     * @param paramName  参数名称
     * @param jsonString
     * @return 对象 @
     */
    public static Object getObjectForJson(final String paramName, final String jsonString) {
        final Map<String, Object> model = MapperUtils.getMapForJson(jsonString);

        return MapUtils.getObject(model, paramName);
    }

    /**
     * 获取键值对
     *
     * @param jsonString
     * @return 键值对 @
     */
    public static Map<String, Object> getMapForJson(final String jsonString) {
        if (StringUtils.isBlank(jsonString)) {
            return null;
        }

        return builderGson(null).fromJson(jsonString, MapperUtils.mapType);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedType 映射类型
     * @param paramName  参数名称
     * @param map
     * @return @
     */
    public static <T> T getBeanForJson(final Type mappedType, final String paramName, final Map<String, Object> map) {
        final Object paramJsonObject = MapUtils.getObject(map, paramName);

        if (paramJsonObject == null) {
            return null;
        }

        return MapperUtils.toBean(mappedType, paramJsonObject);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedType 映射类型
     * @param src        参数名称
     * @return @
     */
    public static <T> T toBean(final Type mappedType, final Object src) {
        return MapperUtils.toBean(mappedType, src, null);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedType  映射类型
     * @param src         参数名称
     * @param datePattern 日期结构
     * @return
     */
    public static <T> T toBean(final Type mappedType, final Object src, final String datePattern) {
        final Gson gson = MapperUtils.builderGson(datePattern);

        final String srcJsonString = gson.toJson(src);

        return gson.fromJson(srcJsonString, mappedType);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedType  映射类型
     * @param paramName   参数名称
     * @param map
     * @param datePattern
     * @return @
     */
    public static <T> T getBeanForJson(final Type mappedType, final String paramName, final Map<String, Object> map, String datePattern) {
        final Object paramJsonObject = MapUtils.getObject(map, paramName);

        if (paramJsonObject == null) {
            return null;
        }

        return MapperUtils.toBean(mappedType, paramJsonObject, datePattern);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedType 映射类型
     * @param paramName  参数名称
     * @param jsonString
     * @return bean @
     */
    public static <T> T getBeanForJson(final Type mappedType, final String paramName, final String jsonString) {
        final Object paramJsonObject = MapperUtils.getObjectForJson(paramName, jsonString);

        if (paramJsonObject == null) {
            return null;
        }

        return MapperUtils.toBean(mappedType, paramJsonObject);
    }

    /**
     * @param mappedClass
     * @param src
     * @return
     */
    public static <T> T getBeanForObject(final Class<T> mappedClass, final Object src) {
        if (src == null) {
            return null;
        }

        Gson gson = builderGson(null);

        final String paramJsonString = gson.toJson(src);

        return gson.fromJson(paramJsonString, TypeToken.of(mappedClass).getType());
    }

    /**
     * 获取bean关于json
     *
     * @param mappedType 映射类型
     * @param jsonString json字符串
     * @return @
     */
    public static <T> T toBean(final Type mappedType, final String jsonString) {
        return MapperUtils.toBean(mappedType, jsonString, null);
    }

    /**
     * 获取bean关于json
     *
     * @param mappedType  映射类型
     * @param jsonString  json字符串
     * @param datePattern 日期结构
     * @return
     */
    public static <T> T toBean(final Type mappedType, final String jsonString, final String datePattern) {
        final Gson gson = MapperUtils.builderGson(datePattern);

        return gson.fromJson(jsonString, mappedType);
    }

    /**
     * 转为json
     *
     * @param src object
     * @return string
     */
    public static String toJson(final Object src) {
        return builderGson(null).toJson(src);
    }

    /**
     * 转为json
     *
     * @param src         object
     * @param datePattern 日期结构
     * @return string
     */
    public static String toJson(final Object src, final String datePattern) {
        final Gson gson = MapperUtils.builderGson(datePattern);

        return gson.toJson(src);
    }
}
